//
// Created by huyi on 24-6-15.
//
#pragma once
#include "AmaInstance.h"
#include "common.h"

#include <DolphinDB.h>
#include <Util.h>

#include <folly/dynamic.h>
#include <folly/logging/xlog.h>

#include <atomic>

namespace tradev::app {

using dolphindb::ConstantSP;
using dolphindb::DATA_TYPE;
using dolphindb::DBConnection;
using dolphindb::DdbVector;
using dolphindb::TableSP;

struct ColumnInfo {
  std::string name;
  DATA_TYPE   type;
};

class QuoteAmaLiteService;

class DolphindbInstance {
public:
  using ColumnInfoVec = std::vector<ColumnInfo>;
  using ColumnNameVec = std::vector<std::string>;
  using ColumnTypeVec = std::vector<dolphindb::DATA_TYPE>;

  /*!
   * @brief
   * @param options
   * @param args
   */
  DolphindbInstance(Options options, Args args)
      : _options(std::move(options))
      , _args(std::move(args)) {}

  ~DolphindbInstance() { close(); }

  /*!
   * @brief
   * @return
   */
  int open();

  /*!
   * @brief
   */
  void close() {
    if (_closed.exchange(true)) {
      return;
    }
    _conn.close();
    XLOG(INFO, "Dolphindb closed.");
  }

  /*! */
  FOLLY_NODISCARD
  bool isAvaliable() const { return !_closed.load(); }

  /*! */
  FOLLY_NODISCARD
  int select1();

  /*!
   * @brief
   * @param script
   * @param priority
   * @param parallelism
   * @param fetchSize
   * @param clearMemory
   * @return
   */
  ConstantSP run(const std::string& script, int priority = 4, int parallelism = 2, int fetchSize = 0, bool clearMemory = false) {
    return _conn.run(script, priority, parallelism, fetchSize, clearMemory);
  }

  /*!
   * @brief
   * @param funcName
   * @param args
   * @param priority
   * @param parallelism
   * @param fetchSize
   * @param clearMemory
   * @return
   */
  ConstantSP run(const std::string& funcName, std::vector<ConstantSP>& args, int priority = 4, int parallelism = 2, int fetchSize = 0, bool clearMemory = false) {
    return _conn.run(funcName, args, priority, parallelism, fetchSize, clearMemory);
  }

  FOLLY_NODISCARD
  ColumnNameVec column_names() const { return _column_names; }

  FOLLY_NODISCARD
  ColumnTypeVec column_types() const { return _column_types; }

private:
  std::atomic_bool _closed{true};

  DBConnection  _conn;
  Options       _options;
  Args          _args;
  ColumnInfoVec _columns;
  ColumnNameVec _column_names;
  ColumnTypeVec _column_types;
};

/*!
 * @brief 用于往ddb写入快照数据
 */
class MdSnapshotAppender {
private:
  QuoteAmaLiteService* _service;

  /*!
   * @brief 缓存数组
   */
  std::vector<ItemPtr> _item_cache;

public:
  explicit MdSnapshotAppender(QuoteAmaLiteService* service)
      : _service(service) {
  }

  /*!
   * @brief
   * @param pItem
   * @return 当前已经缓存的元素个数
   */
  size_t append(ItemPtr&& pItem);

  /*!
   * @brief
   */
  void flush();

  /*!
   * @brief
   */
  FOLLY_NODISCARD
  size_t countCachedRows() const {
    size_t total{0};
    for (const auto& e : _item_cache) {
      switch (e->type) {
      case kMdSnapshot:
      case kMdOptionSnapshot:
      case kMdIndexSnapshot:
      case kMdFutureSnapshot:
        total += e->size;
        break;
      default:
        CHECK(false) << "countCachedRows _item_cache contains unsupport type " << e->type;
        break;
      }
    }
    return total;
  }

private:
  /*!
   * @brief 模板函数,被fillSnapshot调用
   * @tparam T
   * @param table
   * @param rowIdx
   * @param snapshot
   * @param colDateTime
   * @param colLastTime
   * @param bidPri
   * @param askPri
   * @param bidVol
   * @param askVol
   */
  template<class T>
  void fillSnapshotRow(
    const TableSP&      table,
    int                 rowIdx,
    const T*            snapshot,
    const ConstantSP&   colDateTime,
    const ConstantSP&   colLastTime,
    DdbVector<double>&  bidPri,
    DdbVector<double>&  askPri,
    DdbVector<int64_t>& bidVol,
    DdbVector<int64_t>& askVol) {
    // 通用模板实现
    throw std::runtime_error("Unsupported");
  }

  /*!
   * @brief 模板函数
   * @tparam T
   * @param p
   * @param rowIdx
   * @param out
   */
  template<class T>
  void fillSnapshot(T* p, int rowIdx, dolphindb::TableSP& out);

  /*!
   * @brief 处理异常的情况
   */
  void flushFailed();

  template<class T>
  double fixedClosePrice(const T* tick);
};

} // namespace tradev::app
